package core

import (
	"fmt"
	"math/big"

	"gitee.com/caivega/easm/util"
	"github.com/ethereum/go-ethereum/core/vm"
)

type Config struct {
	LabelSize int // the count of bytes for jump addresses
	Debug     bool
}

func CreateConfig() *Config {
	return &Config{1, false}
}

func (c *Config) SetSize(size int) *Config {
	c.LabelSize = size
	return c
}

type Buffer struct {
	data []byte
}

func CreateBuffer() *Buffer {
	return &Buffer{data: make([]byte, 0)}
}

func (buf *Buffer) Len() int {
	return len(buf.data)
}

func (buf *Buffer) Append(ds []byte) {
	buf.data = append(buf.data, ds...)
}

func (buf *Buffer) Write(offset int, ds []byte) {
	ll := len(buf.data)
	ld := len(ds)
	if offset >= (ll - ld) {
		panic("error write the buffer")
	}
	for i := 0; i < ld; i++ {
		buf.data[offset+i] = ds[i]
	}
}

func (buf *Buffer) Bytes() []byte {
	return buf.data
}

func DumpCode(code []byte) {
	DumpCodeWith(code, nil, nil)
}

func DumpCodeWith(code []byte, before func(int, int, []byte), after func(int, int, int, []byte)) {
	fmt.Println("-------------------------")

	lop := -1
	ldata := []byte(nil)
	for i := 0; i < len(code); i++ {
		op := vm.OpCode(code[i])
		ns := util.BytesToHexWith(new(big.Int).SetUint64(uint64(i)).Bytes(), true, 2)
		fmt.Printf("%s ", ns)
		if before != nil {
			before(i, lop, ldata)
		}
		fmt.Printf("%s", op.String())
		args := vm.Immediates(op)
		for j := 0; j < args; j++ {
			if j == 0 {
				fmt.Printf(" ")
			} else {
				fmt.Printf(",")
			}
			data := code[i+j+1]
			fmt.Printf("%#x", data)
		}
		if after != nil {
			after(i, int(op), lop, ldata)
		}
		fmt.Println()

		lop = int(op)
		ldata = code[i+1 : i+1+args]

		i += args
	}
}
